/**
 * @export
 * @class Road
 * @classdesc 道路类
 * @property {Object} 地图容器 - SchoolLab实例
 * @property {String} name - 名称
 * @property {String} color - 颜色
 * @property {Number} opacity - 透明度
 * @property {Number} lineWidth - 道路宽度
 * @property {Number} baseUVYLength - 基准uv
 * @property {Boolean} isAdaption - 是否根据屏幕自适应宽度
 * @property {Array} path - 路径点集
 * @property {Number} renderOrder - 层叠顺序
 * @example
 * var road = new Road(viewer, {
 *   lineWidth: 10,
 *   color: '#ff0000',
 *   opacity: 0.5,
 *   renderOrder: 20,
 *   name: 'road',
 *   path: [],
 *   isAdaption: false
 * })
 */
import { extend } from './util'
import RoadWorker from '../../workers/roadMerge.worker'
import Guid from './Guid'
import Feature from './Feature'
export default class Road {
  constructor(viewer, options) {
    const opts = extend({
      name: "road",
      color: "#ffffff",
      opacity: 1,
      lineWidth: 1,
      baseUVYLength: 100
    }, options)

    /** @member {SchoolLab} - 地图容器 */
    this.viewer = viewer
    
    /** @member {String} - 名称 */
    this.name = opts.name
    
    /** @member {Color} - 颜色 */
    this.color = opts.color
    
    /** @member {Number} - 透明度 */
    this.opacity = opts.opacity
    
    /** @member {Number} - 宽度 */
    this.lineWidth = opts.lineWidth
    
    /** @member {Number} - uv基准 */
    this.baseUVYLength = opts.baseUVYLength
    
    /** @member {Boolean} - 是否根据屏幕自适应宽度 */
    this.isAdaption = opts.isAdaption === undefined ? true : opts.isAdaption
    
    /** @member {Array} - 路径点集 */
    this.path = opts.path
    
    /** @member {THREE.Mesh} - mesh对象 */
    this.entity = null
    
    /** @member {String} - 唯一id标识 */
    this.id = Guid.create()

    Feature.apply(this)

    this._init()
  }

  // 初始化组件
  _init() {
    this.viewer.animationManager.regist(`road_${this.id}`, this._update.bind(this))
    
    let material = this._initMaterial()

    let worker = null
    const self = this
    const mergeLine = function() {
      worker = new RoadWorker()
      worker.postMessage({
        path: self.path,
        gisCenter: self.viewer.gisCenter
      })

      worker.onmessage = function(event) {
        const data = event.data
        const facenormals = data.facenormals
        const positions = data.positions
        const uvs = data.uvs

        const geometry = new THREE.BufferGeometry()
        geometry.setAttribute('facenormal', new THREE.BufferAttribute(facenormals, 3))
        geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
        geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))

        const mesh = new THREE.Mesh(geometry, material)
        mesh.name = self.name
        mesh.renderOrder = self.renderOrder
    
        self.entity = mesh
        self.viewer.world.add(mesh)

        worker.terminate()
        self.viewer.workerQueue.workingNum -= 1
        self.viewer.workerQueue.changeStatus()
      }

      worker.onerror = function(e) {
        console.log('error at ' + e.filename + ':' + e.lineno + e.message)
        worker.terminate()
        self.viewer.workerQueue.workingNum -= 1
        self.viewer.workerQueue.changeStatus()
      }
    }

    self.viewer.workerQueue.addWorker(mergeLine, self)
    self.viewer.workerQueue.changeStatus()
  }

  // 初始化材质
  _initMaterial() {
    const uniforms = {
      resolution: { type: 'v2', value: new THREE.Vector2(this.viewer.box.clientWidth, this.viewer.box.clientHeight) },
      lineWidth: { type: 'f', value: this.lineWidth },
      opacity: { type: 'f', value: this.opacity },
      color: { type: 'c', value: new THREE.Color(this.color) },
      isAdaption: { type: 'b', value: this.isAdaption }
    }

    let vs = this._initVS()
    let fs = this._initFS()
    const material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vs,
      fragmentShader: fs,
      transparent: true,
      depthWrite: false,
      depthTest: true,
      blending: THREE.NormalBlending,
      side: THREE.DoubleSide
    })

    return material
  }

  // 初始化vertexShader
  _initVS() {
    const vs = `
      precision highp float;

      attribute vec3 facenormal;
      varying vec2 vUv;
      uniform float lineWidth;
      uniform vec2 resolution;
      uniform bool isAdaption;
      
      void main(void) {
        vec4 pos=projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        float pixelWidthRatio = 0.;
        float pixelWidth = 0.;
        if (isAdaption) {
          pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]);
          pixelWidth = pos.w * pixelWidthRatio;
        } else {
          pixelWidthRatio = 1. / 1000.;
          pixelWidth = resolution.x * pixelWidthRatio;
        }
        vUv=uv;
        vec3 real_position=position+normalize(facenormal)*lineWidth*pixelWidth;
        vec4 mvPosition = modelViewMatrix * vec4(real_position, 1.0);
        gl_Position = projectionMatrix * mvPosition;
      }
    `
    return vs
  }

  // 初始化FragmentShader
  _initFS() {
    const fs = `
      precision highp float;

      uniform float opacity;
      uniform vec3 color;
      varying vec2 vUv;
      
      void main() {
        gl_FragColor = vec4(color, opacity);
      }
    `
    return fs
  }

  // 更新动画系数
  _update() {
    if (this.entity) {
      this.entity.material.uniforms.resolution.value = new THREE.Vector2(this.viewer.box.clientWidth, this.viewer.box.clientHeight)
    }
  }

  // 组件销毁
  destroy() {
    this._disposeHierarchy(this.entity, this._dispose)
    this.viewer.world.remove(this.entity)
    this.entity = null
    this.viewer.animationManager.unload(`road_${this.id}`)
  }
}
